/**
 * This file is part of iSecurePasswords.
 *
 *   iSecurePasswords is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   iSecurePasswords is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with iSecurePasswords.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * Author: Matthew MacGregor
 * Created: 2012
 * iSecurePasswords, copyright 2013 Sudolink, LLC
 * 
 */ 

package com.sudolink.crypto;

import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;

/**
 * @author dev
 */
public class AESCrypto implements ICrypto {
    
    private final String ALGO = "AES";
    
   
    @Override
    public String encrypt(byte[] data, byte[] password, byte[] salt ) throws CryptoException  {
        try {
            Key key = generateKey(password, salt);
            Cipher c = Cipher.getInstance(ALGO);
            c.init(Cipher.ENCRYPT_MODE, key);
            byte[] encVal = c.doFinal(data);
            Base64 b64 = new Base64();
            String encryptedValue = b64.encodeAsString(encVal);
            return encryptedValue;
        } catch (Exception ex) {
            Logger.getLogger(AESCrypto.class.getName()).log(Level.SEVERE, null, ex);
            throw new CryptoException( ex.getMessage() );
        } 
  
    }
    

    @Override
    public byte[] decrypt(String encryptedData, byte[] password, byte[] salt) throws CryptoException {
        try {
            Key key = generateKey(password, salt);
            Cipher c = Cipher.getInstance(ALGO);
            c.init(Cipher.DECRYPT_MODE, key);
            Base64 b64 = new Base64();
            byte[] decordedValue = b64.decode(encryptedData);
            byte[] decValue = c.doFinal(decordedValue);
            //String decryptedValue = new String(decValue);
            return decValue;
        
        }
        catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException ex) {
            Logger.getLogger(AESCrypto.class.getName()).log(Level.WARNING, "Unable to decrypt the value.");
            throw new CryptoException( ex.getMessage() );
        } 

    }
    
    private Key generateKey( byte[] password, byte[] salt )  {
        DigestUtils du = new DigestUtils();
        String hex = DigestUtils.sha256Hex(password);
        String saltHex = DigestUtils.sha256Hex(salt);
        Key key = new SecretKeySpec(generateInitializationVector(hex, saltHex), ALGO);

        return key;
    }
    
    private byte[] generateInitializationVector( String hex, String saltHex ) {
        byte[] iv = new byte[16];
        for( int i= 16, j=0 ; j < 16; i++, j++ )
        {
            iv[j] = (byte) (hex.charAt(i) + saltHex.charAt( i + 1 ));
        }
        return iv;
    }
    
}
